package com.murphy.gatewaymain.utils;

import cn.hutool.core.lang.TypeReference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

/**
 * 加、解密 验签
 */
public class SignUtil {


	private static final String encoding = "UTF-8";
	private static final String AES_CBC_PKC_ALG = "AES/CBC/PKCS5Padding";
	private static final byte[] AES_IV = initIV(AES_CBC_PKC_ALG);
	private static final String RSA_ECB_PKCS1 = "RSA/ECB/PKCS1Padding";

	/**
	 * 加密算法RSA
	 */
	public static final String KEY_ALGORITHM = "RSA";
	/**
	 * 签名算法 SHA256WithRSA
	 */
	public static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";

	/**
	 * 签名算法 SHA1WithRSA
	 */
	public static final String SIGNATURE_ALGORITHM_SHA1 = "SHA1WithRSA";

	//融担私钥，小贷公钥
	public static Map<String, ImmutablePair<String,String>> keys = new HashMap<>();

	/**
	 * rsa解密
	 *
	 * @param content    加密rsaBase64
	 * @param privateKey rsa私钥
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String decryptByPrivateKey4Pkcs5(byte[] content, String privateKey) throws
			UnsupportedEncodingException {
		Cipher c = null;
		byte[] decryptedData = null;
		try {
			byte[] priByte = Base64Utils.decode(privateKey.getBytes(encoding));

			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(priByte);
			KeyFactory keyF = KeyFactory.getInstance("RSA");
			RSAPrivateKey pk = (RSAPrivateKey) keyF.generatePrivate(keySpec);

			c = Cipher.getInstance(RSA_ECB_PKCS1);
			c.init(Cipher.DECRYPT_MODE, pk);

			byte[] contentB = Base64Utils.decode(new String(content, encoding).getBytes(encoding));
			int inputLen = contentB.length;
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			int offSet = 0;
			byte[] cache;
			int i = 0;
			while (inputLen - offSet > 0) {
				if (inputLen - offSet > 128) {
					cache = c.doFinal(contentB, offSet, 128);
				} else {
					cache = c.doFinal(contentB, offSet, inputLen - offSet);
				}
				out.write(cache, 0, cache.length);
				i++;
				offSet = i * 128;
			}
			decryptedData = out.toByteArray();
			out.close();

		} catch (Exception e) {
			return null;
		}
		return new String(decryptedData, encoding);
	}

	/**
	 * aes解密
	 *
	 * @param content  待解密内容
	 * @param password 解密密钥
	 * @return
	 */
	public static String decrypt4Base64(String content, String password) {
		try {
			byte[] byteContent = Base64Utils.decode(content.getBytes(encoding));
			byte[] enCodeFormat = password.getBytes(encoding);
			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
			Cipher cipher = Cipher.getInstance(AES_CBC_PKC_ALG);// 创建密码�?
			cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(AES_IV));// 初始�?
			byte[] result = cipher.doFinal(byteContent);
			return new String(result, encoding); // 加密
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 验证签名
	 *
	 * @param data
	 * @param publicKey
	 * @param sign
	 * @return
	 * @throws Exception
	 */
	public static boolean verify(byte[] data, String publicKey, String sign)
			throws Exception {
		byte[] keyBytes = Base64Utils.decode(publicKey.getBytes(encoding));
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PublicKey publicK = keyFactory.generatePublic(keySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initVerify(publicK);
		signature.update(data);
		return signature.verify(Base64Utils.decode(sign.getBytes(encoding)));
	}


	/**
	 * 随机数
	 *
	 * @return
	 */
	public static String getRandom() {
		StringBuffer sb = new StringBuffer();
		Random random = new Random();
		for (int i = 0; i < 16; i++) {
			sb.append("1234567890qwertyuiopasdfghjklzxcvbnm".charAt(random
					.nextInt("1234567890qwertyuiopasdfghjklzxcvbnm".length())));
		}
		return sb.toString();
	}

	/**
	 * aes加密
	 *
	 * @param content  加密的内
	 * @param password 加密密码
	 * @return
	 */
	public static String encrypt4Base64(String content, String password) {
		try {
			byte[] bytePwd = password.getBytes(encoding);
			SecretKeySpec key = new SecretKeySpec(bytePwd, "AES");
			Cipher cipher = Cipher.getInstance(AES_CBC_PKC_ALG);// 创建密码
			byte[] byteContent = content.getBytes(encoding);
			cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(AES_IV));// 初始
			byte[] result = cipher.doFinal(byteContent);
			return new String(Base64Utils.encode(result)); // 加密
		} catch (Exception e) {

		}
		return null;
	}

	/**
	 * 公钥加密
	 *
	 * @param data      源数
	 * @param publicKey 公钥(BASE64编码)
	 * @return
	 * @throws Exception
	 */
	public static String encryptByPublicKey4Pkcs5(byte[] data, String publicKey)
			throws Exception {
		byte[] keyBytes = Base64Utils.decode(publicKey.getBytes(encoding));
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		RSAPublicKey publicK = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
		// 对数据加�?
		Cipher cipher = Cipher.getInstance(RSA_ECB_PKCS1);
		cipher.init(Cipher.ENCRYPT_MODE, publicK);
		int inputLen = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段加
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > 128) {
				cache = cipher.doFinal(data, offSet, 128);
			} else {
				cache = cipher.doFinal(data, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * 128;
		}
		byte[] encryptedData = out.toByteArray();

		out.close();
		return new String(Base64Utils.encode(encryptedData));
	}

	/**
	 * 加签
	 * @param data
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	public static String sign(byte[] data, String privateKey) throws Exception {
		byte[] keyBytes = Base64Utils.decode(privateKey.getBytes(encoding));
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initSign(privateK);
		signature.update(data);
		return new String(Base64Utils.encode(signature.sign()));
	}

	/**
	 * 初始化向
	 *
	 * @param aesCbcPkcAlg
	 * @return
	 */
	private static byte[] initIV(String aesCbcPkcAlg) {
		Cipher cp;
		try {
			cp = Cipher.getInstance(aesCbcPkcAlg);
			int blockSize = cp.getBlockSize();
			byte[] iv = new byte[blockSize];
			for (int i = 0; i < blockSize; ++i) {
				iv[i] = 0;
			}
			return iv;

		} catch (Exception e) {
			int blockSize = 16;
			byte[] iv = new byte[blockSize];
			for (int i = 0; i < blockSize; ++i) {
				iv[i] = 0;
			}
			return iv;
		}
	}


	public static Pair<String, String> genKeyPair() throws NoSuchAlgorithmException {
		// KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
		// 初始化密钥对生成器，密钥大小为96-1024位
		keyPairGen.initialize(1024, new SecureRandom());
		// 生成一个密钥对，保存在keyPair中
		KeyPair keyPair = keyPairGen.generateKeyPair();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
		// 得到公钥字符串
		String publicKeyString = new String(Base64Utils.encode(publicKey.getEncoded()));
		// 得到私钥字符串
		String privateKeyString = new String(Base64Utils.encode((privateKey.getEncoded())));

		return Pair.of(privateKeyString, publicKeyString);
	}
	public static void main(String[] args) {
		try {
			String time = "1631774108000";
			String channelId = "10000000";
			String version = "1.0";
			String key = "29on3p02r9yd7qzd";
			String data1 = "{\n" + "    \"applyNo\" : \"GMCMC21092414284406001\"\n" + "}";
			Pair<String, String> stringStringPair = genKeyPair();
			//私钥
			String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANe2bmG2t11hweL4rd48JsBdeyZfRy8phAUqhs8sBi8lHFn8L3+VDkZH35BRPZPzDJ30a2lehBZjL+FXZCWIub16baGQgFjT2Jiod3xCa0uIvFDrpS28NAMb+gcw1VAVFJL1FVHtNKk2GYLQjZUR+oX884mKbtG4e49P9lMH7Z1vAgMBAAECgYALJEAVSfO0ngz+pSuN0/uIagunUrqBhBpujeDCqJp1KuyI9U6av18qYCH6+Uc98grPycUWfyxBX8QkVng0vBgjyfzeboPUbh0MFx5DA5lJ2yMv+oPLXIEjTcA4sVUxoRXLrSSETTGIuigFuNctc4vBx755hxGn1VnBhuEYsvu6MQJBAO51Br/xw3m5trlJN0ko4P7nlziFWhB0wopCGv6tLeQYvkcw98jz+EplARNcTP/0aQrggHM5UPP7cW7j6kp+AQkCQQDnlQwAG2gOJ30cJxMlQH23NE9ju3poUzHUiJ8qOXSHZOVScYP8VWtKfFMWSiQXriIgQ34LsyDLo/k6MJ3TG+C3AkBGfwR61I+0uenCR1n34AT8dx0m0Y251br5wudWKX6qs4H1bA2lNDNQUyIJRj1hYjF3zL1M00ISj2COpwTJ9wx5AkB9Q1CnaiuhpFh29ufTOYwGocPjhVATyBRnCrNVSpiud7PXIVGsFqQfORpULyxQpr8MxpUSTQULQZmYkR19SFIHAkEA4WW+WwuP7PGbwAyjrlcJo6e24zQ0N189zCfqULWnKGTYBm5LhMyJGEmVzjsPb148PD4Z7yGdhrWQtPlfWbCfTQ==";
			System.out.println("private="+privateKey);
			//公钥
			//			String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChX0Edbwk6p21uIjdNfCh8q31z4mEC5w7hxyivjO5eZjopRUYPqDdmIWAc5BquESaRrnYmueKlbvhHxrDRtEIB1RvPL/BnqiF3ShfjTBy8E/rXxF40qe5YfclOnBDM563FvpCwBgSOEnmcajtsR2YLdUtTLAQzkmzcVWZe8wx3mwIDAQAB";
			//国美公钥
			String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXtm5htrddYcHi+K3ePCbAXXsmX0cvKYQFKobPLAYvJRxZ/C9/lQ5GR9+QUT2T8wyd9GtpXoQWYy/hV2QliLm9em2hkIBY09iYqHd8QmtLiLxQ66UtvDQDG/oHMNVQFRSS9RVR7TSpNhmC0I2VEfqF/POJim7RuHuPT/ZTB+2dbwIDAQAB";
			System.out.println("public="+publicKey);
			String randomKey = encryptByPublicKey4Pkcs5(key.getBytes(Charset.forName("UTF-8")), publicKey);

//			OrderResponse orderResponse = new OrderResponse();
//			orderResponse.setOrderNo("order_no0000000000000000001");
//			orderResponse.setDesc("第一个");
//			String data = encrypt4Base64(JSON.toJSONString(orderResponse), key);
//			BaseResponse m = new BaseResponse("1000","成功",data);
//			m.setRandomKey(randomKey);
//			String sign = sign(JSON.toJSONString(m,SerializerFeature.MapSortField).getBytes(Charset.forName("UTF-8")), privateKey);
//			m.setSign(sign);
			//加密
			JSONObject jsonObject = JSON.parseObject(data1);
			String data = encrypt4Base64(jsonObject.toString(), key);
			TreeMap m = new TreeMap();
			m.put("time", time);
			m.put("channelId", channelId);
			m.put("version", version);
			m.put("randomKey", randomKey);
			m.put("data", data);
			String sign = sign(JSON.toJSONString(m).getBytes(Charset.forName("UTF-8")), privateKey);
			m.put("sign", sign);

			System.out.println("------加密加签后数据-----");
			String request = JSON.toJSONString(m);
			System.out.println(request);

			//验签
			JSONObject requestDTO = JSON.parseObject(request);
			Map<String, String> params = JSONObject
					.parseObject(requestDTO.toJSONString(), new TypeReference<Map<String, String>>() {
					});

			TreeMap<String, Object> treeMap = new TreeMap<>(params);
			String sign_ = treeMap.get("sign").toString();
			treeMap.remove("sign");
			boolean verify = SignUtil
					.verify(JSON.toJSONString(treeMap).getBytes(StandardCharsets.UTF_8), publicKey, sign_);
			if (verify) {
				System.out.println("验签通过");
			}
			String key_ = SignUtil.decryptByPrivateKey4Pkcs5(treeMap.get("randomKey").toString().getBytes(StandardCharsets.UTF_8),
					privateKey);
			System.out.println(key_);
			String data_ = decrypt4Base64(treeMap.get("data").toString(), key_);
			System.out.println(data_);

		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}
